#pragma once
#include "AWA2D.h"
class APTS2D :
	public AWA2D
{
protected:
	int** tempOpen;          /* Temporary OPEN used to update OPEN members with new best depth value */

public:

	APTS2D(void) : AWA2D(0,1)
	{
		sprintf(algorithmName,"APTS2D");
		maxCost = calculateMaxCost();
	}

	~APTS2D(void)
	{
	}

	/**
	 Calculate the maximum cost possible
	 **/
	virtual int calculateMaxCost()
	{
		return MAXG+1;
	}

		
	virtual int cost(int h, int g)
	{
		if(bestDepth==MAXG) // Initially like GBFS
			return h;
		else
			return (int)(MAXG*((double)h/(bestDepth-g)));		
	}

	/**
	 * Create a temporary openlist to support re-sorting of OPEN after goal is found.
	 **/
	virtual void setup(int initialState[SIZE])
	{
		AWA2D::setup(initialState);
		tempOpen = new int*[maxCost];
		for (int f = 0; f < maxCost; f++){ /* initialize temp OPEN lists */
			tempOpen[f]=new int[MAXG];
			for(int g=0;g<MAXG;g++){
				tempOpen[f][g] = MAX; 
			}
		}
	}

	/**
	 * Update cost of all OPEN members when an improved goal has been found 
	 **/
	virtual int expandUntilFindGoal()
	{
		int index;
		int newCost;
		int** swapOpen;
		int currenth;
		int currentg;
		int result = AWA2D::expandUntilFindGoal();
		int inOpen=0; // Counts how many states are in OPEN
		int prunned=0; // Counts how many nodes were prunned outof OPEN
		int nextIndex;

		// Update open list
		if (stored < FULL)
		{
			// Clear tempOpen
			for (int f = 0; f < maxCost; f++) /* initialize temp OPEN lists */
				for(int g=0;g<MAXG;g++)
					tempOpen[f][g] = MAX; 
		
			// Calculate new costs for every node in open
			bestf = maxCost;
			bestg = 0;

			for(int f=0;f<maxCost;f++){
				for(int g=0;g<MAXG;g++){
					index = open[f][g];

					while (index != MAX){
						currenth = old[index].h;
						currentg = old[index].g;
						nextIndex = old[index].next; // BUGFIX: Must store old[index].next now, before reinserting index to new open, changing its .next.

						if(currentg+currenth<bestDepth){
							newCost = cost(currenth,currentg);
							if(newCost<bestf){
								bestf=newCost;
								bestg=currentg;
							}
							else if((newCost==bestf) && (bestg<currentg)){
								bestg = currentg;
							}
							inOpen++;
							insertToOpen(index,newCost,tempOpen);
						}
						else{
						 prunned++;
						}
						index = nextIndex;
					}
				}
			}

			/* Setting open to point to the updated open */
			swapOpen=open;
			open=tempOpen;
			tempOpen=swapOpen;		
		}

		return result; 
	}


	/* CLOSE takes an index into the hash table and deletes it from the OPEN list,
	if its there.  
	WHY THIS METHOD WAS OVERRIDEN: After re-sorting OPEN, some nodes are removed from OPEN
	because thay have g+h>bestDepth. Thus, applying cost() on them is meaningless and returns garbage.
	Thus, added here a check: if the g+h>=bestDepth, then the node is not in OPEN and no need to close it.
	Paramerter: int index -  index of the closed node in hash table */
	virtual void close(int index)
	{
		if(old[index].h+old[index].g<bestDepth)
			AWA2D::close(index);
	}

	/** 
	 * Clear dynamic memory 
	 **/
	virtual void clear()
	{
		AWA2D::clear();

		for(int i=0;i<maxCost;i++){
			delete[] tempOpen[i];
		}
		delete[] tempOpen;
	}
};

